﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
using BLL.Services.Books;
using Web.Infrastructure.Models;

namespace Web.Areas.Admin.Models.Books
{
    public class BookEditModel : BaseModel, IValidatableObject
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="BookEditModel" /> class.
        /// </summary>
        /// <param name="book">The book.</param>
        public BookEditModel(Book book)
        {
            ToModel(book, this);
            Authors = book.AuthorIds;
            Categories = book.CategoryIds;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BookEditModel" /> class.
        /// </summary>
        public BookEditModel()
        {
            Authors = new int[0];
            Categories = new int[0];
        }

        /// <summary>
        /// Gets the date.
        /// </summary>
        /// <value>
        /// The date.
        /// </value>
        [ScaffoldColumn(false)]
        public string Date
        {
            get
            {
                return DateOfPublish.ToShortDateString();
            }
        }

        /// <summary>
        /// Gets or sets the book id.
        /// </summary>
        /// <value>
        /// The book id.
        /// </value>
        [UIHint("hidden")]
        [Remote("Validate", "Books", "Admin", AdditionalFields = "Name,Authors", ErrorMessage = "Book with the same name and authors already exists.")]
        public int BookId { get; set; }

        /// <summary>
        /// Gets or sets the name of the file.
        /// </summary>
        /// <value>
        /// The name of the file.
        /// </value>
        [Required(ErrorMessage = @"File name is required!")]
        [Display(Name = "File name")]
        [UIHint("Upload")]
        public string FileName { get; set; }

        /// <summary>
        /// Gets or sets the avatar.
        /// </summary>
        /// <value>
        /// The avatar.
        /// </value>
        [Required(ErrorMessage = @"Avatar name is required!")]
        [Display(Name = "Avatar")]
        [UIHint("Upload")]
        public string Avatar { get; set; }

        /// <summary>
        /// Gets or sets the date of publish.
        /// </summary>
        /// <value>
        /// The date of publish.
        /// </value>
        [Required(ErrorMessage = @"Date of publish is required!")]
        [Display(Name = "Date of publish")]
        public DateTime DateOfPublish { get; set; }

        /// <summary>
        /// Gets or sets the short content.
        /// </summary>
        /// <value>
        /// The short content.
        /// </value>
        [Required(ErrorMessage = @"Short content is required!")]
        [Display(Name = "Short content")]
        [UIHint("MultilineText")]
        [StringLength(1000)]
        public string ShortContent { get; set; }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>
        /// The name.
        /// </value>
        [Required(ErrorMessage = @"Name is required!")]
        [Display(Name = "Name")]
        [Remote("Validate", "Books", "Admin", AdditionalFields = "BookId,Authors", ErrorMessage = "Book with the same name and authors already exists.")]
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets the user id.
        /// </summary>
        /// <value>
        /// The user id.
        /// </value>
        [UIHint("Select")]
        [Display(Name = "User")]
        [Required(ErrorMessage = @"User is required!")]
        [Range(1, int.MaxValue, ErrorMessage = "Please select user.")]
        public int UserId { get; set; }

        /// <summary>
        /// Gets or sets the authors.
        /// </summary>
        /// <value>
        /// The authors.
        /// </value>
        [Required(ErrorMessage = @"Author is required!")]
        [Display(Name = "Authors")]
        [UIHint("MultiSelect")]
        [Remote("Validate", "Books", "Admin", AdditionalFields = "Name,BookId", ErrorMessage = "Book with the same name and authors already exists.")]
        public int[] Authors { get; set; }

        /// <summary>
        /// Gets or sets the categories.
        /// </summary>
        /// <value>
        /// The categories.
        /// </value>
        [Required(ErrorMessage = @"Category is required!")]
        [Display(Name = "Categories")]
        [UIHint("MultiSelect")]
        public int[] Categories { get; set; }

        /// <summary>
        /// Books the specified model.
        /// </summary>
        /// <param name="model">The model.</param>
        public static explicit operator Book(BookEditModel model)
        {
            var book = new Book();
            ToEntity(model, book);
            book.AuthorIds = model.Authors;
            book.CategoryIds = model.Categories;
            return book;
        }

        /// <summary>
        /// Gets the book service.
        /// </summary>
        protected static IBookService BookService
        {
            get
            {
                return DependencyResolver.Current.GetService<IBookService>();
            }
        }

        /// <summary>
        /// Determines whether the specified object is valid.
        /// </summary>
        /// <param name="validationContext">The validation context.</param>
        /// <returns>
        /// A collection that holds failed-validation information.
        /// </returns>
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            var result = new List<ValidationResult>();
            if (!BookService.ValidateBook(BookId, Name, Authors))
            {
                result.Add(new ValidationResult("Book with the same name and authors already exists."));
            }
            if (Authors.Where(x => x != 0).Count() == 0)
                result.Add(new ValidationResult("Please add one or move authors"));

            if (Categories.Where(x => x != 0).Count() == 0)
                result.Add(new ValidationResult("Please add one or move categories"));
            return result;
        }
    }
}